/****************************************************************************
*                                                                           *
* Copyright (c) 2004 - 2007 Nuvoton Electronics Corp. All rights reserved.  *
*                                                                           *
*****************************************************************************/

/****************************************************************************
* FILENAME
*   atapi_test.c
*
* VERSION
*   1.0
*
* DESCRIPTION
*   The ATAPI IDE hard disk test program
*
* DATA STRUCTURES
*   None
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "wbio.h"
#include "wblib.h"
#include "NUC900_reg.h"
//#include "atapireg.h"  
#include "ide.h"

#include "nvtfat.h"


#define DUMMY_BUFFER_SIZE		(64 * 1024)
static UINT32  _pucDummy[DUMMY_BUFFER_SIZE];
UINT32 _pucBuffer[DUMMY_BUFFER_SIZE];
BOOL bHardDiskInited = FALSE;
/****************************************************************************
* FUNCTION
*   Action_WriteSpeedTest
*
* DESCRIPTION
*   Write test for ATAPI by WBFAT
*
* INPUTS
*   suFileName : The file name of unicode
*	szAsciiName : The file name of ascii code
*
* OUTPUTS
*   < 0 : Error
*	> 0 : Success
*
****************************************************************************/
static INT  Action_WriteSpeedTest(CHAR *suFileName, CHAR *szAsciiName)
{
	INT	 	 hFile;
	INT      nWriteLen, nTime0, nStatus;
	UINT32   uKBCnt = 0;

	hFile = fsOpenFile(suFileName, szAsciiName, O_CREATE | O_TRUNC);

	if (hFile < 0)
	{
		sysprintf("Open file error!!\n");
		return hFile;
	}
		
	memset((UINT8 *)_pucDummy, '1', DUMMY_BUFFER_SIZE);
		
	nStatus = 0;
	nTime0 = sysGetTicks(TIMER0);

	while (1)
	{
		nStatus = fsWriteFile(hFile, (UINT8 *)_pucDummy, DUMMY_BUFFER_SIZE, &nWriteLen);
		if (nStatus < 0)
		{
			sysprintf("Write File Error!!\n");
			break;
		}
		
		uKBCnt += nWriteLen / 1024;
		
		if (uKBCnt % 1024 == 0)
			sysprintf("%d MB\r", uKBCnt);
		
		if (uKBCnt >= 40 * 1024)
			break;
	}
	nTime0 = sysGetTicks(TIMER0) - nTime0;
	if (nTime0 == 0) nTime0 = 1;

	sysprintf("Write speed: %d KB/sec\n", (INT)(uKBCnt * 100) / nTime0);
	
	fsCloseFile(hFile);

	return nStatus;
}

/****************************************************************************
* FUNCTION
*   Action_ReadSpeedTest
*
* DESCRIPTION
*   Read test for ATAPI by WBFAT
*
* INPUTS
*   suFileName : The file name of unicode
*	szAsciiName : The file name of ascii code
*
* OUTPUTS
*   < 0 : Error
*	> 0 : Success
*
****************************************************************************/
static INT  Action_ReadSpeedTest(CHAR *suFileName, CHAR *szAsciiName)
{
	INT	 	 hFile;
	INT      nReadLen, nTime0, nStatus;
	UINT32   uKBCnt;

	uKBCnt = 0;

	hFile = fsOpenFile(suFileName, szAsciiName, O_RDONLY);

	if (hFile < 0)
	{
		sysprintf("Open file error!!\n");
		return hFile;
	}
		
	nStatus = 0;
	nTime0 = sysGetTicks(TIMER0);
	while (1)
	{
		nReadLen = 0;
		nStatus = fsReadFile(hFile, (UINT8 *)_pucDummy, DUMMY_BUFFER_SIZE, &nReadLen);
		if ((nStatus < 0) || (nReadLen == 0))
			break;
		
		uKBCnt += nReadLen / 1024;
		
		if (uKBCnt % 1024 == 0)
			sysprintf("%d MB\r", uKBCnt/1024);
	}
	
	nTime0 = sysGetTicks(TIMER0) - nTime0;
	if (nTime0 == 0) nTime0 = 1;

	sysprintf("Read speed: %d KB/sec\n", (INT)(uKBCnt * 100) / nTime0);
	
	fsCloseFile(hFile);
	
	if((uKBCnt / 1024) == 40)
		return 1;
	else
		return nStatus;
}

INT  find_ide_disk()
{
	PDISK_T		*pDiskList, *ptPDiskPtr;
	INT         driveNo;
	
	ptPDiskPtr = pDiskList = fsGetFullDiskInfomation();
	
	while (ptPDiskPtr != NULL)
	{
		if (ptPDiskPtr->nDiskType & (DISK_TYPE_HARD_DISK | DISK_TYPE_DMA_MODE))
		{
			driveNo = ptPDiskPtr->ptPartList->ptLDisk->nDriveNo;
			fsReleaseDiskInformation(pDiskList);
			return driveNo;
		}
		ptPDiskPtr = ptPDiskPtr->ptPDiskAllLink;
	}
	fsReleaseDiskInformation(pDiskList);
	return -1;
}

static INT  Action_Compare(CHAR *suFileName, CHAR *szAsciiName)
{
	INT		hFile;
	INT		nLen, nCount, nStatus;
		
	hFile = fsOpenFile(suFileName, szAsciiName, O_RDONLY);
	if (hFile < 0)
		return hFile;
	
	sysprintf("Comparing file ...\n");
	nCount = 0;
	nStatus = fsReadFile(hFile, (PUINT8)&_pucBuffer[0], DUMMY_BUFFER_SIZE, &nLen);
	if(nStatus != 0)
	{
		sysprintf("Read File Fail!!\n");
		return -1;
	}
	fsCloseFile(hFile);	
	
	if(memcmp(_pucBuffer, _pucDummy, DUMMY_BUFFER_SIZE) == 0)
	{
		sysprintf("File Compare Successfully!!\n");
		return 1;
	}		
	else	
	{	
		sysprintf("File Compare Failed\n");
		return -1;
	}
	
}

/****************************************************************************
* FUNCTION
*   HD_Test
*
* DESCRIPTION
*   Read/write test for ATAPI by WBFAT
*
* INPUTS
*	None
*
* OUTPUTS
*   < 0 : Error
*	> 0 : Success
*
****************************************************************************/
INT HD_Test(void)
{
	CHAR unicodeFileName[] = {'c', 0, ':', 0, '\\', 0, 't', 0, 'e', 0, 's', 0, 't', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0, 0};
	INT driveNo;
	
	driveNo  = find_ide_disk();
	if (driveNo < 0)
	{
		sysprintf("Hard disk not found!!\n");
		return -1;
	}

	unicodeFileName[0] = driveNo;
	
	//ATAPI read/write speed test
	sysprintf(" >>> ATAPI Write Test <<<\n");
	if(Action_WriteSpeedTest(unicodeFileName, NULL) < 0)
	{
		sysprintf("FAIL!!\n\n");
		return -1;
	}
	else
		sysprintf("PASS!!\n\n");
	
	sysprintf(" >>> ATAPI Read Test <<<\n");
	if(Action_ReadSpeedTest(unicodeFileName, NULL) < 0)
	{
		sysprintf("FAIL!!\n\n");
		return -1;
	}
	else
		sysprintf("PASS!!\n\n");
	
	sysprintf(" >>> ATAPI Compare File Test <<<\n");
	if(Action_Compare(unicodeFileName, NULL) < 0)
	{
		sysprintf("FAIL!!\n\n");
		return -1;
	}
	else
		sysprintf("PASS!!\n\n");	
	
	return 1;

}

static INT  HD_init(PDISK_T *ptPDisk)
{

	return 0;
}

static INT  HD_ioctl(PDISK_T *ptPDisk, INT control, VOID *param)
{
	return 0;
}

static INT  HD_read(PDISK_T *ptPDisk, UINT32 uSecNo, 
								INT nSecCnt, UINT8 *pucBuff)
{
    if (!atapiRead(0,(UINT32)pucBuff, uSecNo, nSecCnt))		
   		sysprintf("read error\n");
       
	
	return FS_OK;
}


static INT  HD_write(PDISK_T *ptPDisk, UINT32 uSecNo, 
								INT nSecCnt, UINT8 *pucBuff, BOOL bWait)								
{
    if (!atapiWrite(0,(UINT32)pucBuff, uSecNo, nSecCnt))
   		sysprintf("write error\n");
	
	return FS_OK;
}

STORAGE_DRIVER_T  _HDDriver = 
{
	HD_init,
	HD_read,
	HD_write,
	HD_ioctl,
};


INT  InitHardDisk(INT nEngineClock)
{
	PDISK_T		*ptPDisk;
	UINT32  	sector;	
	int   		retry, t0;
	
	for (retry = 0; retry < 5; retry++)
	{
		if (atapiInit(ATAPI_CLK_66MHZ))
			break;
			
		t0 = sysGetTicks(TIMER0);
		while (sysGetTicks(TIMER0) - t0 < 100)
			;
	}
	
	if (retry >= 5)
	{
	    bHardDiskInited = FALSE;
	    sysprintf("HD not found\n");
	    return 0;
   	}
	
   	atapiIoctl(ATAPI_MASTER, ATAPI_GET_CAPACITY, (UINT32)&sector);
  	sysprintf("\nMaster HD Total sectors : %d\n",sector);
   	sysprintf("Capacity : %2.2fG\n",sector/2000000.);
    
  if(!atapiOpen())
  {
     	bHardDiskInited = FALSE;
     	return 0;
  } 	
	
	ptPDisk = malloc(sizeof(PDISK_T));
	ptPDisk->nDiskType = DISK_TYPE_HARD_DISK | DISK_TYPE_DMA_MODE;
	ptPDisk->uTotalSectorN= sector;
	ptPDisk->uDiskSize = (ptPDisk->uTotalSectorN/1000)<<9;
	ptPDisk->ptDriver = &_HDDriver;
	fsPhysicalDiskConnected(ptPDisk);
	
	bHardDiskInited = TRUE;

	return 1;
}

/****************************************************************************
* FUNCTION
*   diag_atapi
*
* DESCRIPTION
*   The main function used for testing read/writing fucnion of ATAPI interface
*
* INPUTS
*	None
*
* OUTPUTS
*	None
*
****************************************************************************/
INT diag_atapi(void)
{
  
  
  sysprintf("+--------------------------------------------------------+\n");
  sysprintf("|         Nuvoton ATAPI Diagnostic Code                  |\n");
  sysprintf("+--------------------------------------------------------+\n");
  sysprintf("| Note:                                                  |\n"); 
  sysprintf("|    1)Please make sure the ATAPI hard disk is plugged.  |\n");
  sysprintf("|    2)Turn on SW3, turn off SW4.                        |\n");
  sysprintf("+--------------------------------------------------------+\n");
  
  	if (!bHardDiskInited)
  		InitHardDisk(1);
  
  	if (!bHardDiskInited)
  		goto exit;
  	
  /* atapi read/write test */
	if(HD_Test() > 0)
	{	
		sysprintf("\nATAPI Read/Write Test PASS!!\n");
		return 0;
	}
	
exit:
	sysprintf("\nATAPI Read/Write Test FAIL!!\n");

	return 0;
}
